package com.chatim.nonamechatim.config;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.chatim.nonamechatim.common.JwtUtil;
import com.chatim.nonamechatim.common.Res;
import com.chatim.nonamechatim.pojo.User;
import com.chatim.nonamechatim.service.UserService;
import com.chatim.nonamechatim.service.impl.UserServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.concurrent.TimeUnit;


@Configuration
public class SecurityConfig {

    @Resource
    UserServiceImpl userServiceImpl;

    @Resource
    UserService userService;

    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Bean
    LoginFilter loginFilter(){

        LoginFilter loginFilter = new LoginFilter();
        // 登录请求地址
        loginFilter.setFilterProcessesUrl("/login");
        // 成功回调
        loginFilter.setAuthenticationSuccessHandler((req, res, auth) -> {
            // 状态改为在线
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            String name = authentication.getName();
            userService.update(new LambdaUpdateWrapper<User>().eq(User::getUsername, name).set(User::getActiveStatus, 1));
            // 登录成功，生成 JWT 字符串
            String token;
            try {
                token = JwtUtil.createJWT();
                // 在redis中记录登录信息
                String rKey = "token:"+auth.getName();
                stringRedisTemplate.opsForValue().set(rKey, auth.getName());
                // 设置过期时间
                stringRedisTemplate.expire(rKey, JwtUtil.EXPIRE_TIME, TimeUnit.SECONDS);
            } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
                throw new RuntimeException(e);
            }
            res.setContentType("text/html;charset=utf-8");
            res.getWriter().write(JSON.toJSONString(Res.success(token, "登录成功！")));
        });
        // 失败回调
        loginFilter.setAuthenticationFailureHandler((req, res, auth) -> {
            System.out.println("登录失败");
            res.setContentType("text/html;charset=utf-8");
            res.getWriter().write(JSON.toJSONString(Res.error("登录失败！")));
        });
        // 必须指定 authenticationManager，否则会报错
        loginFilter.setAuthenticationManager(authenticationManager());
        // 如果没有定义 loginFilter，系统自动配置UsernamePasswordAuthenticationFilter为其设置SecurityContextRepository
        loginFilter.setSecurityContextRepository(new HttpSessionSecurityContextRepository());

        return loginFilter;
    }

    @Bean
    JwtFilter JwtFilter(){
        return new JwtFilter(stringRedisTemplate);
    }

    @Bean
    PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }

    @Bean
    AuthenticationManager authenticationManager(){
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userServiceImpl);
        return new ProviderManager(provider);
    }

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(a -> a
                                .requestMatchers("/user/register", "/login", "/index.html", "/assets/**", "/header/**")
                                .permitAll()
                                .anyRequest()
                        .authenticated())
                // 注销登录
                .logout(l -> l.logoutUrl("/logout").logoutSuccessHandler((req, res, auth) -> {
                    // 删除redis中的token
                    String rKey = "token:"+auth.getName();
                    stringRedisTemplate.delete(rKey);
                    res.setContentType("application/json;charset=utf-8");
                    res.getWriter().write(JSON.toJSONString(Res.success(true, "退出登录成功！")));
                }))
                .csrf(AbstractHttpConfigurer::disable);

        //将自定义的过滤器放在 UsernamePasswordAuthenticationFilter 过滤器前面
        http.addFilterBefore(loginFilter(), UsernamePasswordAuthenticationFilter.class);
        http.addFilterBefore(JwtFilter(), UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }
}
